#include "TcpServer.h"
#include "InetAddress.h"
#include "Socket.h"
#include "Channel.h"
#include "Connection.h"
#include "Log.h"

#include <iostream>
#include <unistd.h>

TcpServer::TcpServer(const char *ip, const uint16_t port,int thread_num)
    :m_thread_num(thread_num),m_mainloop(new EventLoop(true,5,10)),m_acceptor(m_mainloop.get(), ip, port),m_threadpoll(m_thread_num,"IO")
{
    //m_mainloop = new EventLoop;
    m_mainloop->set_epoll_timeout_callback(std::bind(&TcpServer::epoll_timeout, this, std::placeholders::_1));

    //m_acceptor = new Acceptor(m_mainloop, ip, port);
    m_acceptor.set_callback(std::bind(&TcpServer::new_connection, this, std::placeholders::_1));
    
    //m_threadpoll = new ThreadPool(m_thread_num,"IO");

    for(int i=0;i<thread_num;i++)
    {
        m_subloops.emplace_back(new EventLoop(false,5,10));
        m_subloops[i]->set_epoll_timeout_callback(std::bind(&TcpServer::epoll_timeout, this, std::placeholders::_1));
        m_subloops[i]->set_timer_callback(std::bind(&TcpServer::remove_connection, this, std::placeholders::_1));
        m_threadpoll.add_task(std::bind(&EventLoop::run,m_subloops[i].get()));
    }
}

TcpServer::~TcpServer()
{
    //delete m_acceptor;
    //delete m_mainloop;
    //delete m_threadpoll;

    // for(auto& loop:m_subloops)
    // {
    //     delete loop;
    // }
}

void TcpServer::start()
{
    m_mainloop->run();
}

void TcpServer::new_connection(std::unique_ptr<Socket> clientsock)
{
    //todo 
    ConnectionPtr conn(new Connection(m_subloops[clientsock->fd()%m_thread_num].get(), std::move(clientsock)));
    conn->set_close_callback(std::bind(&TcpServer::close_connection, this, std::placeholders::_1));
    conn->set_error_callback(std::bind(&TcpServer::error_connection, this, std::placeholders::_1));
    
    //LOG(INFO)<<"before new  connection(fd="<<conn->fd()<<",ip="<<conn->ip()<<",port="<<conn->port()<<") ok.";
    conn->set_on_message_callback(std::bind(&TcpServer::on_message, this, std::placeholders::_1, std::placeholders::_2));
    conn->set_send_complete_callback(std::bind(&TcpServer::send_complete, this, std::placeholders::_1));
    
    conn->clientchannel_enableread();

    //LOG(INFO)<<"after new  connection(fd="<<conn->fd()<<",ip="<<conn->ip()<<",port="<<conn->port()<<") ok.";

    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_conns[conn->fd()] = conn;
    }
    m_subloops[conn->fd()%m_thread_num]->add_connection(conn);

    if (m_new_connection_callback)
        m_new_connection_callback(conn);
}

void TcpServer::close_connection(ConnectionPtr conn)
{
    //LOG(INFO)<<"1client(eventfd="<<conn->fd()<<") disconnected.";
    if (m_close_connection_callback)
       m_close_connection_callback(conn);
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_conns.erase(conn->fd());
    }
}
void TcpServer::error_connection(ConnectionPtr conn)
{
    //LOG(INFO)<<"3client(eventfd="<<conn->fd()<<") error.";
    if (m_error_connection_callback)
        m_error_connection_callback(conn);
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_conns.erase(conn->fd());
    }
}

void TcpServer::on_message(ConnectionPtr conn, std::string &message)
{
    if (m_on_message_callback)
        m_on_message_callback(conn, message);
}

void TcpServer::send_complete(ConnectionPtr conn)
{
    if (m_send_complete_callback)
        m_send_complete_callback(conn);
}

void TcpServer::epoll_timeout(EventLoop *loop)
{
    if (m_epoll_timeout_callback)
        m_epoll_timeout_callback(loop);
}

void TcpServer::set_new_connection_callback(std::function<void(ConnectionPtr)> fn)
{
    m_new_connection_callback = fn;
}

void TcpServer::set_close_connection_callback(std::function<void(ConnectionPtr)> fn)
{
    m_close_connection_callback = fn;
}

void TcpServer::set_error_connection_callback(std::function<void(ConnectionPtr)> fn)
{
    m_error_connection_callback = fn;
}

void TcpServer::set_on_message_callback(std::function<void(ConnectionPtr, std::string &)> fn)
{
    m_on_message_callback = fn;
}

void TcpServer::set_send_complete_callback(std::function<void(ConnectionPtr)> fn)
{
    m_send_complete_callback = fn;
}

void TcpServer::set_epoll_timeout_callback(std::function<void(EventLoop *)> fn)
{
    m_epoll_timeout_callback = fn;
}

void TcpServer::remove_connection(int fd)
{
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_conns.erase(fd);
    }
}

void TcpServer::stop()
{
    m_mainloop->stop();
    LOG(INFO)<<"主事件循环停止。";
    for(int i=0;i<m_thread_num;i++)
        m_subloops[i]->stop();
    LOG(INFO)<<"从事件循环停止。";
    m_threadpoll.stop();
    LOG(INFO)<<"IO线程停止。";
}